package com.ac.scum.log.task.face.config;

import com.ac.common.core.io.FileUtils;
import com.ac.scum.config.bean.ServerFTPFileConfigEconomy;
import com.ac.scum.log.bean.Server;
import com.ac.scum.log.bean.ServerFTP;
import com.ac.scum.log.task.mapper.config.ServerFTPFileConfigEconomyMapper;
import com.ac.scum.log.task.mapper.server.ServerFTPMapper;
import com.ac.scum.log.task.service.ServerService;
import com.ac.scum.log.task.utils.ftp.FTPFile;
import com.ac.scum.log.task.utils.ftp.FTPUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
import io.micrometer.common.util.StringUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.dromara.x.file.storage.core.platform.AliyunOssFileStorage;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@AllArgsConstructor
public class EconomyFTPSyncTask {
    private final ServerService serverService;
    private final RedissonClient redissonClient;
    private final ServerFTPMapper serverFTPMapper;
    private final ServerFTPFileConfigEconomyMapper serverFTPFileConfigEconomyMapper;
    private final FileStorageService fileStorageService;

    private final String FileName = "EconomyOverride.json";
    private static final ThreadPoolTaskExecutor threadPool;

    static {
        threadPool = new ThreadPoolTaskExecutor();
        threadPool.setCorePoolSize(20);
        threadPool.setMaxPoolSize(40);
        threadPool.setQueueCapacity(Integer.MAX_VALUE);
        threadPool.setKeepAliveSeconds(60);
        threadPool.setThreadNamePrefix("config-update-consumer-");
        threadPool.setWaitForTasksToCompleteOnShutdown(true);
        threadPool.initialize();
    }

    @Scheduled(cron = "0 */5 * * * ?")
    @Transactional
    public void syncStart() {
        List<Server> servers = serverService.getServersWithSpecifiedPackageIds(1L);
        if (!servers.isEmpty()) {
            for (Server server : servers) {
                threadPool.submit(() -> {
                    RLock lock = redissonClient.getLock("server-config-economy-async-server-lock-" + server.getId().toString());
                    if (lock.isLocked()) {
                        return;
                    }
                    try {
                        lock.lock(5, TimeUnit.MINUTES);
                        async(server);
                    } catch (Exception e) {
                        log.error("同步商人文件出现异常 {}", e.getMessage());
                    } finally {
                        lock.unlock();
                    }
                });
            }
        }
    }

    public void async(Server server) throws JSchException, IOException, SftpException {
        ServerFTP serverFTP = serverFTPMapper.selectOne(Wrappers.lambdaQuery(ServerFTP.class).eq(ServerFTP::getServerId, server.getId()));
        if (serverFTP == null) {
            return;
        }
        ServerFTPFileConfigEconomy serverFTPFileConfigEconomy = serverFTPFileConfigEconomyMapper.selectOne(Wrappers.lambdaQuery(ServerFTPFileConfigEconomy.class).eq(ServerFTPFileConfigEconomy::getServerId, server.getId()));
        if (serverFTPFileConfigEconomy == null) {
            serverFTPFileConfigEconomy = new ServerFTPFileConfigEconomy();
            serverFTPFileConfigEconomy.setServerId(server.getId());
            serverFTPFileConfigEconomy.setAsyncId("0");
        }
        FTPUtil ftpUtil = new FTPUtil(serverFTP);
        ftpUtil.connect();
        Optional<FTPFile> first = ftpUtil.listFiles(serverFTP.getConfigPath()).stream().filter(e -> e.getName().equalsIgnoreCase(FileName)).findFirst();
        if (first.isPresent()) {
            if (!first.get().getSize().toString().equals(serverFTPFileConfigEconomy.getAsyncId())) {

                //如果有之前的文件，删除
                if (StringUtils.isNotBlank(serverFTPFileConfigEconomy.getFileUrl())) {
                    AliyunOssFileStorage aliyunOssFileStorage = fileStorageService.getFileStorage();
                    aliyunOssFileStorage.getClient().deleteObject(aliyunOssFileStorage.getBucketName(), serverFTPFileConfigEconomy.getFileUrl().replace("https://ac-scum-log-config.oss-cn-beijing.aliyuncs.com/",""));
                }
                String remoteFilePath = serverFTP.getConfigPath() + File.separator + FileName;
                String localFilePath = "/" + server.getId() + "-" + FileName;
                try {
                    //下载至本地
                    ftpUtil.downloadFile(remoteFilePath, localFilePath);
                } catch (IOException | SftpException ex) {
                    log.error("同步文件商人文件，下载时出现异常", ex);
                    ftpUtil.disconnect();
                    FileUtils.deleteFile(localFilePath);
                    return;
                }

                FileInfo upload = fileStorageService.of(new File(localFilePath)).setPath(server.getId().toString() + "/").setName(FileName).upload();
                if (upload == null) {
                    log.error("文件上传OSS 失败");
                    FileUtils.deleteFile(localFilePath);
                    return;
                }
                FileUtils.deleteFile(localFilePath);
                serverFTPFileConfigEconomy.setFileUrl(upload.getUrl().replace("-internal", ""));
                serverFTPFileConfigEconomy.setAsyncId(first.get().getSize().toString());
                serverFTPFileConfigEconomy.setSyncTime(LocalDateTime.now());

                if (serverFTPFileConfigEconomy.getId() == null) {
                    serverFTPFileConfigEconomyMapper.insert(serverFTPFileConfigEconomy);
                } else {
                    serverFTPFileConfigEconomyMapper.updateById(serverFTPFileConfigEconomy);
                }
                log.info("{} 商人文件 同步完成", server.getName());
            }
        }

    }

    @Scheduled(cron = "0/2 * * * * ?")
    @Transactional
    public void syncToGame() {
        List<Server> servers = serverService.getServersWithSpecifiedPackageIds(1L);
        if (!servers.isEmpty()) {
            for (Server server : servers) {
                threadPool.submit(() -> {
                    RLock lock = redissonClient.getLock("server-config-economy-async-game-server-lock-" + server.getId().toString());
                    if (lock.isLocked()) {
                        return;
                    }
                    try {
                        lock.lock(5, TimeUnit.MINUTES);
                        asyncToGame(server);
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    } finally {
                        lock.unlock();

                    }
                });
            }
        }
    }

    public void asyncToGame(Server server) throws JSchException, IOException {
        ServerFTP serverFTP = serverFTPMapper.selectOne(Wrappers.lambdaQuery(ServerFTP.class).eq(ServerFTP::getServerId, server.getId()));
        if (serverFTP == null) {
            return;
        }
        ServerFTPFileConfigEconomy serverFTPFileConfigEconomy = serverFTPFileConfigEconomyMapper.selectOne(Wrappers.lambdaQuery(ServerFTPFileConfigEconomy.class)
                .eq(ServerFTPFileConfigEconomy::getServerId, server.getId())
                .eq(ServerFTPFileConfigEconomy::getUpdateFlag, Boolean.TRUE));

        if (serverFTPFileConfigEconomy != null) {
            FTPUtil ftpUtil = new FTPUtil(serverFTP);
            ftpUtil.connect();
            String remoteFilePath = serverFTP.getConfigPath() + File.separator + FileName;
            fileStorageService.download(serverFTPFileConfigEconomy.getFileUrl()).inputStream(inputStream -> {
                try {
                    ftpUtil.uploadFile(inputStream, remoteFilePath);
                } catch (IOException | SftpException e) {
                    ftpUtil.disconnect();
                    log.error("上传商人配置文件时出现异常", e);
                }
            });
            ftpUtil.disconnect();
            serverFTPFileConfigEconomy.setUpdateFlag(Boolean.FALSE);
            serverFTPFileConfigEconomy.setSyncTime(LocalDateTime.now());
            serverFTPFileConfigEconomyMapper.updateById(serverFTPFileConfigEconomy);

        }

    }
}
